<template>
  <div class="webrtc-box" v-show="status">
    <audio id="music1">
        <source src="@/assets/voice/calling.mp3">
      </audio>
      <audio id="music2">
        <source src="@/assets/voice/guaduan.mp3">
      </audio>
    <video v-show="localStream && is_video" class="localvideo" ref="localvideo" autoplay playsinline  muted></video>
    <video v-show="remoteStream && is_video" class="remotevideo" ref="remotevideo" autoplay playsinline></video>
    <div>
      <div class="call-user" v-if="caller">
        <img class="avatar" v-if="status!=2 || !is_video" :src="caller.avatar" alt="">
        <div class="text"> 
          <b v-if="!is_video && status==2">{{caller.displayName}}</b>
          <span v-if="status!=2">
            <span v-if="isReceived"> {{caller.displayName}} 正在请求与您{{is_video ? '视频' : '语音'}}通话</span>
            <span v-else>您正对 <b>{{caller.displayName}}</b> 发起{{is_video ? '视频' : '语音'}}通话</span>   
          </span>
        </div>
        <div class="call-time" v-if="callTime && status==2">
					  {{setCallTime()}}
				  </div>
      </div>
      <div class="calling-button">
        <div class="button" v-if="caller && status==3" >
          <img class="image" src="@/assets/img/webrtc/jieting.png" @click="answer()"/>
          <div class="text">接听</div>
        </div>
        <div class="button" v-if="status==2" >
          <img class="image-icon" :src="voiceStatus ? voiceIcon : voiceOffIcon" @click="switchVoice()"/>
        </div>
        <div class="button" v-if="caller && status!=0" >
          <img class="image" src="@/assets/img/webrtc/guaduan.png" @click="hangup(true)"/>
          <div class="text">挂断</div> 
        </div>
        <div class="button" v-if="status==2" >
          <img class="image-icon" v-if="is_video" :src="videoStatus ? videoIcon : videoOffIcon" @click="switchVideo()"/>
          <div class="image-icon" v-else></div>
        </div>
      </div>
    </div>
  </div>
</template>
  
<script>

export default {
  name: "webrtc",
  props: {
    contact: {
      type: Object,
      default: {},
    },
    userInfo: {
      type: Object,
      default: {},
    },
    config: {
      type: Object,
      default: {},
    },
    alias:{
      type:String,
      default:'raingad'
    }
  },
  data() {
    return {
      voiceIcon:require('@/assets/img/webrtc/voice.png'),
      voiceOffIcon:require('@/assets/img/webrtc/voice-off.png'),
      videoIcon:require('@/assets/img/webrtc/camera.png'),
      videoOffIcon:require('@/assets/img/webrtc/camera-off.png'),
      pc: null,           //peer实例
      status: 0,          //状态0，默认，1：拨号中，2通话中，3来电中
      localVideo: "",    //本地视频的DOM
      remoteVideo: "",   //远程视频的DOM
      remoteStream: null, // 远端视频流
      localStream: null,  // 本地视频流
      caller: null,       //来电用户
      is_video: 1,        //是否为视频通话
      isReceived: false,  //是否为接听者
      videoStatus: true,  //视频开启状态
      voiceStatus: true,  //语音开启状态
      cutdown: 40,        //拨号超时
      timer: null,         //计时器
      offerParams:{},
      callTime:0, //通话时间
      timerIntervalId:null,  //通话计时器
    };
  },
  mounted() {
    this.localVideo = this.$refs.localvideo;
    this.remoteVideo = this.$refs.remotevideo; 
  },
  methods: {
    // 初始化webrtc
    initPeer(stream){
        let opt = this.config;
        let config = {
            'iceServers': [{
                'urls': ['stun:stun.xten.com', 'stun:stun.l.google.com:19302', 'stun:stun1.l.google.com:19302',
                  'stun:stun2.l.google.com:19302', 'stun:stun3.l.google.com:19302', 'stun:stun4.l.google.com:19302'
                ]
              },{
                  'urls': (opt.stun ?? '') ? [opt.stun] : ['stun:stun.callwithus.com'], // 自己搭建服务器地址
                  "username": opt.stunUser ?? null,
                  "credential": opt.stunPass ?? null
              }
            ],
          };
        this.pc = new RTCPeerConnection(config);
        // 接收视频流
        this.pc.ontrack = (event) => {
          if(this.localVideo){
            this.remoteStream = event.streams[0];
            this.remoteVideo.srcObject = event.streams[0];
          }
        };
        this.localStream = stream;
        stream.getTracks().forEach((track) => {
          this.pc.addTrack(track, stream);
        });
        this.localVideo.srcObject = this.localStream;
    },
    // 初始化本地媒体
    initLocalStream(call_id, is_video) {
      this.offerParams = is_video ? {
				  offerToRecieveAudio: 1,
				  offerToRecieveVideo: 1
				} : {
				  offerToRecieveAudio: 1,
				  offerToRecieveVideo: 0
			  }
      let video=is_video==1 ? true : false;
      var getUserMedias = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
      getUserMedias({ video: video, audio: {echoCancellation: true} }, (stream) => {
        this.initPeer(stream);
        // 拨打电话
        if (call_id) {
          // 发起通话请求
          this.$emit('message',{event:'calling'});
          // 拨打中
          this.status = 1;
          // 计时器，如果一段时间没有接听则自动挂断
          this.timer = setInterval(() => {
            this.cutdown--;
            if (this.cutdown == 0) {
              this.hangup(true);
            }
          }, 1000)
        // 接听电话
        } else {
          // 初始化完成后告诉对方已经接听电话
          this.$emit('message',{ event: 'acceptRtc',code:904});
          this.startTime();
        }
      },(err) => {
        let text= is_video==1 ? '摄像头' : '麦克风';
        this.$message.error('请连接'+text+'设备，并开启'+text+'权限');
        this.caller=null;
        this.hangup(false);
      });
    },
    // 拨打电话
    called(is_video) {
      console.log(this.status,this.caller);
      // 如果状态不为0则不允许拨打电话
      if (this.status || this.caller) {
        return false;
      }
      this.is_video = is_video;
      this.caller = this.contact;
      this.initLocalStream(true, is_video);
      this.playMusicCall('state');
    },
    // 接听电话
    answer() {
        this.status = 2;
        this.initLocalStream(false, this.is_video);
        this.playMusicCall('close');
    },
    // 处理接收到的消息
    // 开始通话计时
    startTime() {
      this.timerIntervalId=setInterval(()=>{
        this.callTime++
      },1000)
      },
    // 设置通话时间
    setCallTime(){
      let time=this.callTime;
      const hours = Math.floor(time / 3600);
      const minutes = Math.floor((time - (hours * 3600)) / 60);
      const seconds = time - (hours * 3600) - (minutes * 60);
      return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
    },
    // 挂断电话
    hangup(btn) {
      clearInterval(this.timer);
      clearInterval(this.timerIntervalId);
      // 如果不再通话中才需要取消播放铃声
      if(this.status!=2){
        this.playMusicCall('close');
      }
      // 通话取消
      let code=902;
      // 通话中挂断
      if(this.status==2 ){
        code=906
        // 拒绝挂断
      }else if(this.status==3 ){
        code=903
        //对方忙线中
      }else if(this.status==4 ){
        code=907
      }
      if (this.status) {
        this.status = 0;         //重置通话状态
        this.closeLocalMedia();  //关闭本地媒体
        this.remoteStream=null;  //关闭远程媒体
        this.playMusicHandup();  // 播放挂断音
        this.isReceived = false; //重置是否为接听者
        this.caller = null;      //重置通话对象
        this.voiceStatus=true;
        this.videoStatus=true;
      }
      this.$emit('message',{event:'hangup',code:code,isbtn:btn,callTime:this.callTime});
      //重置通话时间
      this.callTime=0; 
    },
    // 关闭本地媒体
    closeLocalMedia() {
      if (this.localStream && this.localStream.getTracks()) {
        this.localStream.getTracks().forEach((track) => {
          track.stop();
        });
      }
      this.localStream = null;
    },
    // 静音
    switchVoice() {
      if (this.localStream == null) {
        alert('请打开音视频');
        return false;
      }
      const tracks = this.localStream.getTracks();
      if (this.voiceStatus) {
        tracks.forEach(track => {
          if (track.kind === 'audio') {
            track.enabled = false
          }
        });
        this.voiceStatus = false;
      } else {
        tracks.forEach(track => {
          if (track.kind === 'audio') {
            track.enabled = true
          }
        });
        this.voiceStatus = true;
      }
    },
    // 临时开、关视频
    switchVideo() {
      if (this.localStream == null) {
        alert('请打开音视频');
        return false;
      }
      const tracks = this.localStream.getTracks();
      if (this.videoStatus) {
        tracks.forEach(track => {
          if (track.kind === 'video') {
            track.enabled = false
          }
        });
        this.videoStatus = false;
      } else {
        tracks.forEach(track => {
          if (track.kind === 'video') {
            track.enabled = true
          }
        });
        this.videoStatus = true;
      }
    },
    webrtcAction(msg){
      let e=msg.extends;
      switch (e.event) {
        case "calling":
          // 来电了
          this.caller = msg.fromUser;
          this.is_video = parseInt(e.type);
          this.status = 3;
          this.isReceived = true;
          this.playMusicCall('state');
          break;
        case "hangup":
          this.hangup(false);
          break;
        case "busy":
          this.status=4;
            this.hangup(false);
          break;
        case "acceptRtc": //已经接听，创建offer并发送
          this.status = 2;
          clearInterval(this.timer);
          this.startTime();
          this.playMusicCall('close');
          this.createOffer();
          // 创建offer需要监听ice流
          this.onicecandidate();
          break;
        case "turndown":
          break;
        case "answer":
          //同步answer信息...
          this.pc.setRemoteDescription(new RTCSessionDescription({
            type: 'answer',
            sdp:  e.sdp
          }));
          break;	
        case "iceCandidate":
          setTimeout(() => {
            // 添加ice完成通话连接
            if (typeof(e.iceCandidate) === 'object') {
              this.pc.addIceCandidate(new RTCIceCandidate(e.iceCandidate));
            } else {
              this.pc.addIceCandidate(new RTCIceCandidate(JSON.parse(e.iceCandidate)));
            }
          },100)
          break;
        case "offer":
          this.pc.setRemoteDescription(new RTCSessionDescription({
            type: 'offer',
            sdp: e.sdp
          }));
          this.createAnswer()
          break;
        
      }
    },
    // 创建offer-sdp
    createOffer() {
      this.pc.createOffer(this.offerParams).then((offer) => {
        this.pc.setLocalDescription(offer);
        // 发送offer请求
          this.$emit('message',{
            event: 'offer',
            sdp: offer.sdp
          });
      });
    },
    // 创建应答sdp
    createAnswer() {
      this.pc.createAnswer(this.offerParams).then((answer) => {
        this.pc.setLocalDescription(answer);
        // 发送回答请求
        this.$emit('message',{
          event: 'answer',
          sdp: answer.sdp
        });
        this.onicecandidate();
      });
    },
    onicecandidate(){
      this.pc.onicecandidate = (event) => {
          var iceCandidate = event.candidate;
          if (iceCandidate) {
            // 发送请求
            this.$emit('message',{
              event: 'iceCandidate',
              iceCandidate: JSON.parse(JSON.stringify(iceCandidate))
            });
          }
        };
    },
    // 播放响铃
    playMusicCall(type) {
      var audio = document.getElementById("music1");
      if(type === "close"){
        return audio.pause(); // 暂停
      } 
      if (type === "state") {
        audio.loop = true;
      }else {
        audio.loop = false;
      }
      if (audio.paused) {
        audio.play(); // 播放
      } else {
        audio.pause(); // 暂停
      }
    },
    // 播放挂断音
    playMusicHandup() {
      var audio = document.getElementById("music2");
      audio.play(); // 播放
    }
  }

};
</script>
<style scoped lang="scss">
.webrtc-box{
  background: #fff;
  padding:20px 5px 10px;
  border-radius: 6px;
  width:300px;
  max-height:600px;
  position: fixed;
  right:20px;
  bottom: 20px;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
  z-index:99999;
  .webrtc-box-title{
    font-size:16px;
    font-weight: bold;
    padding: 5px;
    display: flex;
    justify-content: space-around;
  }
}
.localvideo{
    width:300px;
    height:200px;
}
.remotevideo{
    width:300px;
    height:200px;
}
.calling-button{
  display: flex;
  justify-content: space-around;
  padding: 20px;
  .button{
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    .image{
      width:60px;
      height:60px;
      margin-bottom: 10px;
    }
    .image-icon{
      width:30px;
      height:30px;
      margin-bottom: 10px;
    }
  }
}
.call-user{
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
  .avatar{
    width:60px;
    height:60px;
    object-fit: contain;
    border-radius: 50%;
    overflow: hidden;
  }
  .text{
    font-size:16px;
    margin-top:15px;
  }
}
.call-time{
  color:#999;
  font-size: 24px;
  text-align: center;
}
</style>
  